/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*                                                                           */
/*    Copyright (C) 2011 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    MCP3422/3/4 18-bit multi channel ADC driver                            */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Include files
#include <drvI2C.h>
#include <drvHMC5883.h>
#include <drvIOConfig.h>

///////////////////////////////////////////////////////////////////////////////
// Constants
#define HMC5883_GENERATE_FUNCTION_NAME_PREFIX(x,y,z) x ## y ## z
#define HMC5883_I2C_Start(x,y,z)     HMC5883_GENERATE_FUNCTION_NAME_PREFIX(drv, x, Start)((y),(z))
#define HMC5883_I2C_WriteByte(x,y)   HMC5883_GENERATE_FUNCTION_NAME_PREFIX(drv, x, WriteByte)(y)
#define HMC5883_I2C_Restart(x,y,z)   HMC5883_GENERATE_FUNCTION_NAME_PREFIX(drv, x, Restart)((y),(z))
#define HMC5883_I2C_ReadByte(x,y)    HMC5883_GENERATE_FUNCTION_NAME_PREFIX(drv, x, ReadByte)(y)
#define HMC5883_I2C_Stop(x)          HMC5883_GENERATE_FUNCTION_NAME_PREFIX(drv, x, Stop)()

///////////////////////////////////////////////////////////////////////////////
//! Initializes MCP324x device
void drvHMC5883Init(void)
{
   InitHMC5883I2C();
}

///////////////////////////////////////////////////////////////////////////////
//! Sets HMC5883 device configration byte
//! \param Configuration byte goes to Config A register
//! \param Configuration byte goes to Config B register
//! \return dosTrue if configuration bytes were successfully updated
dosBool drvHMC5883SetConfiguration(dosByte in_config_a, dosByte in_config_b)
{
	dosBool ack = HMC5883_I2C_Start(HMC5883_I2C, drvI2C_WRITE, drvHMC5883_BASE_ADDRESS);

  if( ack )
  {
  	HMC5883_I2C_WriteByte(HMC5883_I2C, drvHMC5883_CONFIG_REG_A);
		HMC5883_I2C_WriteByte(HMC5883_I2C, in_config_a);
		HMC5883_I2C_WriteByte(HMC5883_I2C, in_config_b);
	}      

	HMC5883_I2C_Stop(HMC5883_I2C);
    
	return ack;
}

///////////////////////////////////////////////////////////////////////////////
//! Sets HMC5883 device configration byte
//! \param Mode register value
//! \return dosTrue if mode byte were successfully updated
dosBool drvHMC5883SetMode(dosByte in_mode)
{
	dosBool ack = HMC5883_I2C_Start(HMC5883_I2C, drvI2C_WRITE, drvHMC5883_BASE_ADDRESS);

  if( ack )
  {
  	HMC5883_I2C_WriteByte(HMC5883_I2C, drvHMC5883_MODE_REG);
		HMC5883_I2C_WriteByte(HMC5883_I2C, in_mode);
	}      

	HMC5883_I2C_Stop(HMC5883_I2C);
    
	return ack;
}

///////////////////////////////////////////////////////////////////////////////
//! Reads HMC5883 device ID bytes
//! \param Magnetic field strength of X axis
//! \param Magnetic field strength of Y axis
//! \param Magnetic field strength of Z axis
//! \return dosTrue if values were red successfully
dosBool drvHMC5883ReadValues(dosWord* out_x, dosWord* out_y, dosWord* out_z)
{
	dosByte status;
	dosBool ack = dosFalse;
	dosByte retry = 3;
	
	do
	{   
		ack = HMC5883_I2C_Start(HMC5883_I2C, drvI2C_WRITE, drvHMC5883_BASE_ADDRESS);
	  if( ack )
	  {
			HMC5883_I2C_WriteByte(HMC5883_I2C, drvHMC5883_DATAOUT_XMSB_REG);
			HMC5883_I2C_Restart(HMC5883_I2C, drvI2C_READ, drvHMC5883_BASE_ADDRESS);
	   
			// read X value
			*out_x = HMC5883_I2C_ReadByte(HMC5883_I2C, drvI2C_ACK) << 8;
			*out_x |= HMC5883_I2C_ReadByte(HMC5883_I2C, drvI2C_ACK);
			
			// read Y value
			*out_y = HMC5883_I2C_ReadByte(HMC5883_I2C, drvI2C_ACK) << 8;
			*out_y |= HMC5883_I2C_ReadByte(HMC5883_I2C, drvI2C_ACK);
	
			// read Z value
			*out_z = HMC5883_I2C_ReadByte(HMC5883_I2C, drvI2C_ACK) << 8;
			*out_z |= HMC5883_I2C_ReadByte(HMC5883_I2C, drvI2C_ACK);
			
			// read status byte
			status = HMC5883_I2C_ReadByte(HMC5883_I2C, drvI2C_NACK);
		}
		
		HMC5883_I2C_Stop(HMC5883_I2C);
		
		retry--;
		
	}	while( retry > 0 && ack && (status & drvHMC5883_STATUS_RDY) == 0 );

	
	return ack;
}

///////////////////////////////////////////////////////////////////////////////
//! Reads HMC5883 device ID bytes
//! \return Device ID value
dosDWord drvHMC5883ReadID(void)
{
	dosWord i = 0;
	dosByte value;
	dosByte id_length = 3;
	dosDWord retval = 0;
   
	dosBool ack = HMC5883_I2C_Start(HMC5883_I2C, drvI2C_WRITE, drvHMC5883_BASE_ADDRESS);
  if( ack )
  {
		HMC5883_I2C_WriteByte(HMC5883_I2C, drvHMC5883_DATAOUT_IDA_REG);
		HMC5883_I2C_Restart(HMC5883_I2C, drvI2C_READ, drvHMC5883_BASE_ADDRESS);
   
		// read block  
		for(i = 0; i < id_length; i++)
		{
			value = HMC5883_I2C_ReadByte(HMC5883_I2C, (i==id_length-1)?drvI2C_NACK:drvI2C_ACK);
			
			retval |= (value << (i*8));
		}
	}

	HMC5883_I2C_Stop(HMC5883_I2C);
	
	return retval;
}

